package com.ultrapower.mapper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.client.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ultrapower.bean.DotBean;
import com.ultrapower.buffer.Buffer;
import com.ultrapower.buffer.OffsetFixedBuffer;
import com.ultrapower.util.BytesUtils;
import com.ultrapower.util.CommonUtils;
import com.ultrapower.util.HBaseTables;
import com.ultrapower.util.TransactionId;

/**
 */
public class TransactionIdMapper implements RowMapper<List<DotBean>> {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    // @Autowired
    // private AbstractRowKeyDistributor rowKeyDistributor;

    @Override
    public List<DotBean> mapRow(Result result, int rowNum) throws Exception {
        if (result.isEmpty()) {
            return Collections.emptyList();
        }
        Cell[] rawCells = result.rawCells();
        List<DotBean> traceIdList = new ArrayList<>(rawCells.length);
        for (Cell cell : rawCells) {
            final byte[] qualifierArray = cell.getQualifierArray();
            final int qualifierOffset = cell.getQualifierOffset();
            final int qualifierLength = cell.getQualifierLength();
            // increment by value of key
            TransactionId traceId = parseVarTransactionId(qualifierArray, qualifierOffset, qualifierLength);
            
            final Buffer valueBuffer = new OffsetFixedBuffer(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
            int elapsed = valueBuffer.readVInt();
            int exceptionCode = valueBuffer.readSVInt();
            String agentId = valueBuffer.readPrefixedString();
            long reverseAcceptedTime = BytesUtils.bytesToLong(cell.getRowArray(), cell.getRowOffset() + HBaseTables.APPLICATION_NAME_MAX_LEN + HBaseTables.APPLICATION_TRACE_INDEX_ROW_DISTRIBUTE_SIZE);
            long acceptedTime = CommonUtils.recoveryTimeMillis(reverseAcceptedTime);

            DotBean dotBean=new DotBean(traceId, acceptedTime, elapsed, exceptionCode, agentId);
            traceIdList.add(dotBean);
            
            logger.debug("found traceId {}", traceId);
        }
        return traceIdList;
    }

    public static TransactionId parseVarTransactionId(byte[] bytes, int offset, int length) {
        if (bytes == null) {
            throw new NullPointerException("bytes must not be null");
        }
        final Buffer buffer = new OffsetFixedBuffer(bytes, offset, length);
        
        // skip elapsed time (not used) hbase column prefix - only used for filtering.
        // Not sure if we can reduce the data size any further.
        // buffer.readInt();
        
        String agentId = buffer.readPrefixedString();
        long agentStartTime = buffer.readSVLong();
        long transactionSequence = buffer.readVLong();
        return new TransactionId(agentId, agentStartTime, transactionSequence);
    }
}
